package com.dragon.common.modules.uaa.utils;

import lombok.Data;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

public class CaptchaGenerator {

    // 默认参数
    private static final int DEFAULT_WIDTH = 120;
    private static final int DEFAULT_HEIGHT = 40;
    private static final int DEFAULT_CODE_COUNT = 4;
    private static final int DEFAULT_NOISE_POINTS = 50;
    private static final int DEFAULT_LINE_COUNT = 3;
    private static final float DEFAULT_SHEAR_FACTOR = 0.2f;
    private static final Color[] DEFAULT_COLORS = {
            new Color(0, 100, 0),     // 深绿
            new Color(128, 0, 0),     // 深红
            new Color(0, 0, 139),     // 深蓝
            new Color(139, 69, 19)    // 棕色
    };

    /**
     * 生成验证码图片的Base64编码
     *
     * @param config
     * @param captchaText
     * @return
     * @throws IOException
     */
    public static String generateCaptchaBase64(CaptchaConfig config, String captchaText) throws IOException {
        BufferedImage image = createCaptchaImage(config, captchaText);
        return convertToBase64(image);
    }

    /**
     * 创建验证码图片
     *
     * @param config
     * @param captchaText
     * @return
     */
    private static BufferedImage createCaptchaImage(CaptchaConfig config, String captchaText) {
        // 1. 创建图像缓冲区
        BufferedImage image = new BufferedImage(config.width, config.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        // 2. 设置背景色（随机浅色）
        g.setColor(getRandomLightColor());
        g.fillRect(0, 0, config.width, config.height);

        // 3. 绘制干扰元素
        drawNoise(g, config);
        drawInterferenceLines(g, config);

        // 4. 生成并绘制验证码文字
        drawText(g, captchaText, config);

        g.dispose();
        return image;
    }

    /**
     * 绘制验证码文字
     *
     * @param g
     * @param text
     * @param config
     */
    private static void drawText(Graphics2D g, String text, CaptchaConfig config) {
        // 计算字体大小（基于图像高度）
        int fontSize = (int) (config.height * 0.6);
        Font font = new Font("Arial", Font.BOLD, fontSize);
        g.setFont(font);

        // 计算字符间距
        int charSpacing = config.width / (text.length() + 1);

        // 绘制每个字符（带随机扭曲）
        for (int i = 0; i < text.length(); i++) {
            // 随机颜色（从配置的颜色数组中选取）
            Color color = config.colors[ThreadLocalRandom.current().nextInt(config.colors.length)];
            g.setColor(color);

            // 字符扭曲变换
            AffineTransform shear = new AffineTransform();
            shear.shear(
                    ThreadLocalRandom.current().nextDouble(-config.shearFactor, config.shearFactor),
                    ThreadLocalRandom.current().nextDouble(-config.shearFactor, config.shearFactor)
            );
            g.setTransform(shear);

            // 计算字符位置（垂直居中）
            int x = charSpacing * (i + 1) - fontSize / 2;
            int y = (int) ((config.height - fontSize) * 0.5 + fontSize * 0.8);

            // 绘制字符
            g.drawString(String.valueOf(text.charAt(i)), x, y);

            // 重置变换
            g.setTransform(new AffineTransform());
        }
    }

    /**
     * 绘制干扰元素
     *
     * @param g
     * @param config
     */
    private static void drawNoise(Graphics2D g, CaptchaConfig config) {
        Random rand = ThreadLocalRandom.current();
        for (int i = 0; i < config.noisePoints; i++) {
            int x = rand.nextInt(config.width);
            int y = rand.nextInt(config.height);
            int dotSize = rand.nextInt(3) + 1;

            Color color = config.colors[rand.nextInt(config.colors.length)];
            g.setColor(color);
            g.fillOval(x, y, dotSize, dotSize);
        }
    }

    /**
     * 绘制干扰线
     *
     * @param g
     * @param config
     */
    private static void drawInterferenceLines(Graphics2D g, CaptchaConfig config) {
        Random rand = ThreadLocalRandom.current();
        for (int i = 0; i < config.lineCount; i++) {
            int x1 = rand.nextInt(config.width / 2);
            int y1 = rand.nextInt(config.height);
            int x2 = rand.nextInt(config.width);
            int y2 = rand.nextInt(config.height);

            // 随机透明度
            Color color = new Color(
                    rand.nextInt(256),
                    rand.nextInt(256),
                    rand.nextInt(256),
                    rand.nextInt(100) + 50
            );

            g.setColor(color);
            g.setStroke(new BasicStroke(rand.nextInt(2) + 1f));
            g.drawLine(x1, y1, x2, y2);
        }
    }

    /**
     * 生成随机验证码文本
     *
     * @param length
     * @return
     */
    public static String generateRandomText(int length) {
        // 去除容易混淆的字符（0/O, 1/I/l等）
        String chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnopqrstuvwxyz";
        StringBuilder sb = new StringBuilder();
        Random rand = ThreadLocalRandom.current();
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(rand.nextInt(chars.length())));
        }
        return sb.toString();
    }

    /**
     * 生成随机浅色颜色
     *
     * @return
     */
    private static Color getRandomLightColor() {
        Random rand = ThreadLocalRandom.current();
        return new Color(
                rand.nextInt(100) + 155,  // R: 155-255
                rand.nextInt(100) + 155,  // G: 155-255
                rand.nextInt(100) + 155   // B: 155-255
        );
    }

    /**
     * 将图像转换为Base64编码
     *
     * @param image
     * @return
     * @throws IOException
     */
    private static String convertToBase64(BufferedImage image) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", baos);
        return "data:image/png;base64," + Base64.getEncoder().encodeToString(baos.toByteArray());
    }

    // 配置类（Builder模式）
    @Data
    public static class CaptchaConfig {
        private final int width;
        private final int height;
        private final int codeCount;
        private final int noisePoints;
        private final int lineCount;
        private final float shearFactor;
        private final Color[] colors;

        private CaptchaConfig(Builder builder) {
            this.width = builder.width;
            this.height = builder.height;
            this.codeCount = builder.codeCount;
            this.noisePoints = builder.noisePoints;
            this.lineCount = builder.lineCount;
            this.shearFactor = builder.shearFactor;
            this.colors = builder.colors;
        }

        public static class Builder {
            private int width = DEFAULT_WIDTH;
            private int height = DEFAULT_HEIGHT;
            private int codeCount = DEFAULT_CODE_COUNT;
            private int noisePoints = DEFAULT_NOISE_POINTS;
            private int lineCount = DEFAULT_LINE_COUNT;
            private float shearFactor = DEFAULT_SHEAR_FACTOR;
            private Color[] colors = DEFAULT_COLORS;

            public Builder width(int width) {
                this.width = width;
                return this;
            }

            public Builder height(int height) {
                this.height = height;
                return this;
            }

            public Builder codeCount(int codeCount) {
                this.codeCount = codeCount;
                return this;
            }

            public Builder noisePoints(int noisePoints) {
                this.noisePoints = noisePoints;
                return this;
            }

            public Builder lineCount(int lineCount) {
                this.lineCount = lineCount;
                return this;
            }

            public Builder shearFactor(float shearFactor) {
                this.shearFactor = shearFactor;
                return this;
            }

            public Builder colors(Color[] colors) {
                this.colors = colors;
                return this;
            }

            public CaptchaConfig build() {
                return new CaptchaConfig(this);
            }
        }
    }
}